package com.nulldev.util.networking.npacket4.iprotocols.ncryptx.testing;

import java.util.List;
import java.util.UUID;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.ByteUtil;
import com.nulldev.util.networking.ip.IP;
import com.nulldev.util.networking.npacket4.nPacket;
import com.nulldev.util.networking.npacket4.iprotocols.ncryptx.KeyExchangeMethod;
import com.nulldev.util.networking.npacket4.iprotocols.ncryptx.nCryptKeyShare;
import com.nulldev.util.networking.npacket4.iprotocols.ncryptx.nCryptKeyShareMeta;
import com.nulldev.util.networking.rudp.Client;
import com.nulldev.util.networking.rudp.Connection;
import com.nulldev.util.networking.rudp.DataReceivedListener;
import com.nulldev.util.networking.rudp.Message;
import com.nulldev.util.networking.rudp.Server;

public class nCryptXTest {

	public static void main(String[] args) {
		final int port = IP.nextFreePort(9000, 13000);
		final Server s = new Server(port, "localhost", 32);
		s.startServer();
		s.registerServerListener(new DataReceivedListener() {

			@Override
			public void receivedMessage(Message message, final Connection connection) {
				final byte[] o = message.getData();
				try {
					final nPacket np = nPacket.createPacketFromBytes(o);
					switch (np.getPacketID()) {
						case "ncryptx.key_share_meta": {
							final nCryptKeyShareMeta ksm = new nCryptKeyShareMeta(np);
							JVM.println("[SERVER] NCRYPT_VERSION: " + ksm.getCryptVersion());
							JVM.println("[SERVER] NCRYPT_SUPPORTED_KEMs:");
							JVM.println(ksm.getMethods());
							s.sendReliablePacketToClient(new nCryptKeyShareMeta(new KeyExchangeMethod[]
								{ KeyExchangeMethod.NCRYPTX1_NEWHOPE, KeyExchangeMethod.PKPK_KEY_EXCHANGE, KeyExchangeMethod.NCRYPTX1_SIDH_DHE,
										KeyExchangeMethod.NCRYPTX1_DHE_CURVE25519, KeyExchangeMethod.SHARED_KEY_EXCHANGE,
										KeyExchangeMethod.NCRYPTX1_INSEC_RNG_KEY_GEN, }),
									connection.getConnectionID());
							break;
						}
						case "ncryptx.key_share": {
							final nCryptKeyShare ks = new nCryptKeyShare(np);
							JVM.println("[SERVER] CLIENT_METHOD: " + ks.getMethod());
							JVM.println("[SERVER] CLIENT_PUBLIC_KEY: " + ByteUtil.getHex(ks.publicKey()));
							JVM.println("[SERVER] CLIENT_PRIVATE_KEY: " + ByteUtil.getHex(ks.privateKey()));
							final nCryptKeyShare keys = new nCryptKeyShare(ks.getMethod());
							s.sendReliablePacketToClient(keys, connection.getConnectionID());
							JVM.println("[SERVER] PUBLIC_KEY: " + ByteUtil.getHex(keys.publicKey()));
							JVM.println("[SERVER] PRIVATE_KEY: " + ByteUtil.getHex(keys.privateKey()));
							break;
						}
						default: {
							JVM.println(np);
							break;
						}
					}
				} catch (Exception e) {
					JVM.errorln(e);
				}
			}

			@Override
			public void disconnected(UUID connectionId) {
			}

			@Override
			public void connected(Connection connection) {

			}
		});
		final Client c = new Client(port, "localhost");
		c.registerClientListener(new DataReceivedListener() {

			@Override
			public void receivedMessage(Message message, Connection conn) {
				final byte[] o = message.getData();
				try {
					final nPacket np = nPacket.createPacketFromBytes(o);
					switch (np.getPacketID()) {
						case "ncryptx.key_share_meta": {
							final nCryptKeyShareMeta ksm = new nCryptKeyShareMeta(np);
							JVM.println("[CLIENT] NCRYPT_VERSION: " + ksm.getCryptVersion());
							JVM.println("[CLIENT] NCRYPT_SUPPORTED_KEMs:");
							JVM.println(ksm.getMethods());
							final List<KeyExchangeMethod> kems = ArrayUtils.toArrayList(ksm.getMethods());
							kems.sort((a, b) -> {
								return a.getRating().compareTo(b.getRating());
							});
							final KeyExchangeMethod selected = kems.get(0);
							JVM.println("[CLIENT] Using: " + selected);
							final nCryptKeyShare keys = new nCryptKeyShare(selected);
							c.sendReliablePacket(keys);
							JVM.println("[CLIENT] PUBLIC_KEY: " + ByteUtil.getHex(keys.publicKey()));
							JVM.println("[CLIENT] PRIVATE_KEY: " + ByteUtil.getHex(keys.privateKey()));
							break;
						}
						case "ncryptx.key_share": {
							final nCryptKeyShare ks = new nCryptKeyShare(np);
							JVM.println("[CLIENT] SERVER_METHOD: " + ks.getMethod());
							JVM.println("[CLIENT] SERVER_PUBLIC_KEY: " + ByteUtil.getHex(ks.publicKey()));
							JVM.println("[CLIENT] SERVER_PRIVATE_KEY: " + ByteUtil.getHex(ks.privateKey()));
							break;
						}
						default: {
							JVM.println(np);
							break;
						}
					}
				} catch (Exception e) {
					JVM.errorln(e);
				}
			}

			@Override
			public void disconnected(UUID connectionId) {
			}

			@Override
			public void connected(Connection connection) {
			}
		});
		c.startClient();
		c.sendReliablePacket(new nCryptKeyShareMeta(new KeyExchangeMethod[]
			{ KeyExchangeMethod.NCRYPTX1_NEWHOPE, KeyExchangeMethod.NCRYPTX1_SIDH_DHE, KeyExchangeMethod.PKPK_KEY_EXCHANGE,
					KeyExchangeMethod.NCRYPTX1_DHE_CURVE25519, KeyExchangeMethod.SHARED_KEY_EXCHANGE, KeyExchangeMethod.NCRYPTX1_INSEC_RNG_KEY_GEN }));
	}

}
